package utils

import (
	"fmt"
	"io"
	"net"
	"os"
	"path/filepath"
	"time"

	"cashway.com/cis/assistant/model"
	"github.com/pkg/sftp"
	"github.com/sirupsen/logrus"
	"golang.org/x/crypto/ssh"
)

// 获取一个STFP客户端连接
func Connect(params model.CreateSftpConnectionParams) (*sftp.Client, error) {

	authMethodPool := make([]ssh.AuthMethod, 0)
	if params.Password != "" {
		authMethodPool = append(authMethodPool, ssh.Password(params.Password))
	} else if params.KeyPath != "" {
		authMethod, err := publicKeyAuthFunc(params.KeyPath)
		if err != nil {
			return nil, err
		}
		authMethodPool = append(authMethodPool, authMethod)
	}

	if params.Timeout <= 0 {
		params.Timeout = 60
	}

	config := &ssh.ClientConfig{
		User:            params.User,
		Auth:            authMethodPool,
		Timeout:         time.Duration(params.Timeout) * time.Second,
		HostKeyCallback: hostKeyCallback,
	}

	// 连接SSH服务端
	addr := fmt.Sprintf("%s:%d", params.Host, params.Port)
	client, err := ssh.Dial("tcp", addr, config)
	if err != nil {
		logrus.Info("连接SSH服务端失败")
		return nil, err
	}

	// 创建SFTP客户端
	sftpClient, err := sftp.NewClient(client)
	if err != nil {
		logrus.Info("创建SFTP客户端失败")
		return nil, err
	}
	return sftpClient, nil
}

// 上传文件
func SftpUploadFile(params *model.SftpUploadFileParams) error {
	sftpClient, err := Connect(params.CreateSftpConnectionParams)
	if err != nil {
		logrus.Info("创建SFTP连接失败")
		return err
	}

	// 打开本地文件
	file, err := os.Open(params.LocalFilePath)
	if err != nil {
		logrus.Infof("打开本地文件失败：%s", params.LocalFilePath)
		return err
	}
	defer file.Close()

	// 创建远程文件夹
	remoteFileName := filepath.Join(params.RemotePath, filepath.Base(params.LocalFilePath))
	if params.TempFileSuffix == "" {
		params.TempFileSuffix = ".tmp"
	}
	tempRemoteFileName := remoteFileName + params.TempFileSuffix
	err = sftpClient.MkdirAll(params.RemotePath)
	if err != nil {
		logrus.Infof("创建远程文件夹失败：%s", params.RemotePath)
		return err
	}

	// 创建远程文件，先写入临时文件
	dstFile, err := sftpClient.Create(tempRemoteFileName)
	if err != nil {
		logrus.Infof("创建远程文件失败：%s", tempRemoteFileName)
		return err
	}
	defer dstFile.Close()

	// 读取本地文件
	bf, err := io.ReadAll(file)
	if err != nil {
		logrus.Infof("读取本地文件失败：%s", params.LocalFilePath)
		return err
	}

	// 写入到远程文件
	_, writeFileErr := dstFile.Write(bf)
	if writeFileErr != nil {
		logrus.Infof("写入远程文件失败：%s", tempRemoteFileName)
		return writeFileErr
	}

	// 修改为目标文件名
	renameErr := sftpClient.Rename(tempRemoteFileName, remoteFileName)
	if renameErr != nil {
		logrus.Infof("修改远程文件名 %s 为 %s 失败", tempRemoteFileName, remoteFileName)
		return renameErr
	}
	return nil
}

// 获取签名
func publicKeyAuthFunc(keyPath string) (ssh.AuthMethod, error) {
	// 读取密钥文件
	keyFile, err := os.Open(keyPath)
	if err != nil {
		return nil, err
	}
	key, err := io.ReadAll(keyFile)
	if err != nil {
		fmt.Printf("密钥文件读取失败%s", keyPath)
		return nil, err
	}
	// 签名
	signer, err := ssh.ParsePrivateKey(key)
	if err != nil {
		fmt.Printf("关键签名失败%s", keyPath)
		return nil, err
	}
	return ssh.PublicKeys(signer), nil
}

func hostKeyCallback(hostname string, remote net.Addr, key ssh.PublicKey) error {
	return nil
}
